/**
责任链模式（Chain of Responsibility Pattern）

意图：避免请求发送者与接收者耦合在一起，让多个对象都有可能接收请求，将这些对象连接成一条链，并且沿着这条链传递请求，直到有对象处理它为止。
主要解决：职责链上的处理者负责处理请求，客户只需要将请求发送到职责链上即可，无须关心请求的处理细节和请求的传递，所以职责链将请求的发送者和请求的处理者解耦了。
何时使用：在处理消息的时候以过滤很多道。
如何解决：拦截的类都实现统一接口。
*/
main(List<String> args) {
  AbstractLogger loggerChain = LoggerFactory.getChainOfLoggers();

  loggerChain.logMessage(AbstractLogger.INFO, "This is an information.");
  loggerChain.logMessage(
      AbstractLogger.DEBUG, "This is a debug level information.");
  loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information.");
}

//////////////////////////////////////////////////////////////////

///
/// 创建抽象的记录器类
///
abstract class AbstractLogger {
  static int INFO = 1;
  static int DEBUG = 2;
  static int ERROR = 3;

  int _level;

  //责任链中的下一个元素
  AbstractLogger _nextLogger;

  void setNextLogger(AbstractLogger nextLogger) {
    this._nextLogger = nextLogger;
  }

  void logMessage(int level, String message) {
    if (this._level <= level) {
      write(message);
    }
    if (_nextLogger != null) {
      _nextLogger.logMessage(level, message);
    }
  }

  void write(String message);
}

///
/// 创建扩展了该记录器类的实体类
///
class ConsoleLogger extends AbstractLogger {
  ConsoleLogger(int level) {
    this._level = level;
  }

  @override
  void write(String message) {
    print("Standard Console::Logger: $message");
  }
}

class ErrorLogger extends AbstractLogger {
  ErrorLogger(int level) {
    this._level = level;
  }

  @override
  void write(String message) {
    print("Error Console::Logger: $message");
  }
}

class FileLogger extends AbstractLogger {
  FileLogger(int level) {
    this._level = level;
  }

  @override
  void write(String message) {
    print("File::Logger: $message");
  }
}

class LoggerFactory {
  static AbstractLogger getChainOfLoggers() {
    AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
    AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
    AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);

    return errorLogger;
  }
}
